home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / By the Book / Mac C Primer V1 / Primer V1 Projects (T7) / 6.1 - Reminder / Reminder.c next >
Encoding:
C/C++ Source or Header  |  1994-04-22  |  17.6 KB  |  807 lines  |  [TEXT/KAHL]

  1. /********************************************************/
  2. /*                                                        */
  3. /*  Reminder Code from Chapter Six of                    */
  4. /*                                                        */
  5. /*    *** The Macintosh Programming Primer, 2nd Ed. ***    */
  6. /*                                                      */
  7. /*    Copyright 1992, Dave Mark and Cartwright Reed       */
  8. /*                                                        */
  9. /********************************************************/
  10.  
  11. /********************************************************/
  12. /*     This copy of Reminder has a change not found in        */
  13. /*    the first printing of the book. The original code    */
  14. /*    worked under System 7, but broke under                */
  15. /*    System 7.1...                                        */
  16. /*                            Dave and Cart, 6/92            */
  17. /********************************************************/
  18.  
  19. #include <Notification.h>
  20. #include <Processes.h>
  21. #include <Aliases.h>
  22.  
  23. #define kBaseResID            128
  24. #define kMoveToFront        (WindowPtr)-1L
  25. #define kSleep                3600L
  26. #define kLeaveWhereItIs        false
  27. #define kUseDefaultProc        (void *) -1L
  28.  
  29. #define kNotANormalMenu        -1
  30.  
  31. #define mApple                kBaseResID
  32. #define iAbout                1
  33.  
  34. #define mFile                kBaseResID+1
  35. #define iSetReminder        1
  36. #define iCancelReminder        2
  37. #define iQuit                4
  38.  
  39. #define mHours                100
  40. #define mMinutes            101
  41. #define mAMorPM                102
  42. #define    mReminders            103
  43.  
  44. #define kDialogResID        kBaseResID+1
  45.  
  46. #define iHoursPopup            4
  47. #define iMinutesPopup        5
  48. #define iAMorPMPopup        6
  49.  
  50. #define iMessageText        8
  51.  
  52. #define iSoundCheckBox        9
  53. #define iRotateCheckBox        10
  54. #define iLaunchCheckBox        11
  55.  
  56. #define iAppNameText        12
  57.  
  58. #define kOn                    1
  59. #define kOff                0
  60.  
  61. #define kMarkApp            1
  62.  
  63. #define kAM                    1
  64. #define kPM                    2
  65.  
  66. #define kMinTextPosition    0
  67. #define kMaxTextPosition    32767
  68.  
  69. #define kDisableButton        255
  70. #define kEnableButton        0
  71.  
  72.  
  73. typedef struct
  74. {
  75.     QElem        queue;
  76.     NMRec        notify;
  77.     FSSpec        file;
  78.     short        hour;
  79.     short        minute;
  80.     Boolean        launch;
  81.     Str255        alert;
  82.     Str255        menuString;
  83.     short        menuItem;
  84.     Boolean        dispose;
  85.     Boolean        wasPosted;
  86. }  ReminderRec, *ReminderPtr;
  87.  
  88.  
  89. /***************/
  90. /*  Functions  */
  91. /***************/
  92.  
  93. void            ToolBoxInit( void );
  94. void            MenuBarInit( void );
  95. void            EventLoop( void );
  96. void            DoEvent( EventRecord *eventPtr );
  97. void             HandleNull( void );
  98. void            HandleMouseDown( EventRecord *eventPtr );
  99. void            HandleMenuChoice( long menuChoice );
  100. void            HandleAppleChoice( short item );
  101. void            HandleFileChoice( short item );
  102.  
  103. ReminderPtr        HandleDialog( void );
  104.  
  105. void            GetFileName( StandardFileReply *replyPtr );
  106.  
  107. pascal    void    LaunchResponse( NMRecPtr notifyPtr );
  108. pascal    void    NormalResponse( NMRecPtr notifyPtr );
  109.  
  110. void            CopyDialogToReminder( DialogPtr dialog, ReminderPtr reminder );
  111.  
  112. ReminderPtr        GetFirstReminder( void );
  113. ReminderPtr        GetNextReminder( ReminderPtr reminder );
  114. ReminderPtr        GetReminderFromNotification( NMRecPtr notifyPtr );
  115.  
  116. ReminderPtr        FindReminderOnMenu( short menuItem );
  117. ReminderPtr        FindReminderToPost( short hour, short minute );
  118. ReminderPtr        FindReminderToDispose( void );
  119.  
  120. void            SetupReminderMenu( void );
  121. short            CountRemindersOnMenu( void );
  122. void            RenumberTrailingReminders( ReminderPtr reminder );
  123. void            InsertReminderIntoMenu( ReminderPtr reminder );
  124. void            ScheduleReminder( ReminderPtr reminder );
  125. void            PostReminder( ReminderPtr reminder );
  126. void            DeleteReminderFromMenu( ReminderPtr reminder );
  127. void            DeleteReminder( ReminderPtr reminder );
  128. ReminderPtr        DisposeReminder( ReminderPtr reminder );
  129.  
  130. void            ConcatString( Str255 str1, Str255 str2);
  131.     
  132.  
  133. /*************/
  134. /*  Globals  */
  135. /*************/
  136.  
  137. Boolean        gDone;
  138. QHdr        gReminderQueue;
  139. NMUPP        gLaunchResponseUPP, gNormalResponseUPP;
  140.  
  141.  
  142. /******************************** main *********/
  143.  
  144. void        main( void )
  145. {
  146.     ToolBoxInit();
  147.     MenuBarInit();
  148.     
  149.     gLaunchResponseUPP = NewNMProc( LaunchResponse );
  150.     gNormalResponseUPP = NewNMProc( NormalResponse );
  151.     
  152.     EventLoop();
  153. }
  154.  
  155.  
  156. /*********************************** ToolBoxInit */
  157.  
  158. void    ToolBoxInit( void )
  159. {
  160.     InitGraf( &qd.thePort );
  161.     InitFonts();
  162.     InitWindows();
  163.     InitMenus();
  164.     TEInit();
  165.     InitDialogs( 0L );
  166.     InitCursor();
  167. }
  168.  
  169.  
  170. /*********************************** MenuBarInit */
  171.  
  172. void    MenuBarInit( void )
  173. {
  174.     Handle            menuBar;
  175.     MenuHandle        menu;
  176.     
  177.     menuBar = GetNewMBar( kBaseResID );
  178.     if ( menuBar == nil )
  179.     {
  180.         SysBeep( 20 );
  181.         ExitToShell();
  182.     }
  183.         
  184.     SetMenuBar( menuBar );
  185.  
  186.     menu = GetMenu( mReminders );
  187.     InsertMenu( menu, kNotANormalMenu );
  188.     
  189.     menu = GetMHandle( mApple );
  190.     AddResMenu( menu, 'DRVR' );
  191.     
  192.     DrawMenuBar();
  193. }
  194.  
  195.  
  196. /*********************************** EventLoop  */
  197.  
  198. void    EventLoop( void )
  199. {        
  200.     EventRecord        event;
  201.     
  202.     gDone = false;
  203.     
  204.     while ( gDone == false )
  205.     {
  206.         if ( WaitNextEvent( everyEvent, &event, GetCaretTime(), nil ) )
  207.             DoEvent( &event );
  208.         else
  209.             HandleNull();
  210.     }
  211. }
  212.  
  213.  
  214. /*********************************** DoEvent  */
  215.  
  216. void    DoEvent( EventRecord *eventPtr )
  217. {
  218.     char    theChar;
  219.     
  220.     switch ( eventPtr->what )
  221.     {
  222.         case mouseDown: 
  223.             HandleMouseDown( eventPtr );
  224.             break;
  225.         case keyDown:
  226.         case autoKey:
  227.             theChar = eventPtr->message & charCodeMask;
  228.             if ( (eventPtr->modifiers & cmdKey) != 0 ) 
  229.                 HandleMenuChoice( MenuKey( theChar ) );
  230.             break;
  231.     }
  232. }
  233.  
  234.  
  235. /****************** HandleNull **********************/
  236.  
  237. void    HandleNull( void )
  238. {
  239.     unsigned long    time;
  240.     DateTimeRec        dateTime;
  241.     ReminderPtr        theReminder;
  242.     
  243.     GetDateTime( &time );
  244.     Secs2Date( time, &dateTime );
  245.  
  246.     theReminder = FindReminderToPost( dateTime.hour, dateTime.minute );
  247.     while ( theReminder )
  248.     {
  249.         PostReminder( theReminder );
  250.         DeleteReminderFromMenu( theReminder );
  251.         theReminder = FindReminderToPost ( dateTime.hour, dateTime.minute );
  252.     }
  253.     
  254.     theReminder = FindReminderToDispose();
  255.     while ( theReminder )
  256.     {
  257.         DisposeReminder( theReminder );
  258.         theReminder = FindReminderToDispose ();
  259.     }
  260. }
  261.  
  262.  
  263. /****************** HandleMouseDown ***********************/
  264.  
  265. void    HandleMouseDown( EventRecord *eventPtr )
  266. {
  267.     WindowPtr        window;
  268.     short            thePart;
  269.     long            menuChoice;
  270.     
  271.     thePart = FindWindow( eventPtr->where, &window );
  272.     switch ( thePart )
  273.     {
  274.         case inMenuBar:
  275.             SetupReminderMenu();
  276.             menuChoice = MenuSelect( eventPtr->where );
  277.             HandleMenuChoice( menuChoice );
  278.             break;
  279.         case inSysWindow: 
  280.             SystemClick( eventPtr, window );
  281.             break;
  282.     }
  283. }
  284.  
  285.  
  286. /******************** SetupReminderMenu *************************/
  287.  
  288. void    SetupReminderMenu( void )
  289. {
  290.     MenuHandle    fileMenu;
  291.     short        items;
  292.     
  293.     fileMenu = GetMenu( mFile );
  294.     items = CountRemindersOnMenu();
  295.     if ( items ) EnableItem( fileMenu, iCancelReminder);
  296.     else DisableItem( fileMenu, iCancelReminder);
  297. }
  298.  
  299.  
  300. /****************** HandleMenuChoice ***********************/
  301.  
  302. void    HandleMenuChoice( long menuChoice )
  303. {
  304.     short    menu;
  305.     short    item;
  306.     ReminderPtr reminder;
  307.     
  308.     if ( menuChoice != 0 )
  309.     {
  310.         menu = HiWord( menuChoice );
  311.         item = LoWord( menuChoice );
  312.         
  313.         switch ( menu )
  314.         {
  315.             case mApple:
  316.                 HandleAppleChoice( item );
  317.                 break;
  318.             case mFile:
  319.                 HandleFileChoice( item );
  320.                 break;
  321.             case mReminders:
  322.                 reminder = FindReminderOnMenu( item );
  323.                 if ( reminder )
  324.                     DeleteReminder( reminder );
  325.                 break;
  326.         }
  327.         HiliteMenu( 0 );
  328.     }
  329. }
  330.  
  331.  
  332. /****************** HandleAppleChoice ***********************/
  333.  
  334. void    HandleAppleChoice( short item )
  335. {
  336.     MenuHandle    appleMenu;
  337.     Str255        accName;
  338.     short        accNumber;
  339.     
  340.     switch ( item )
  341.     {
  342.         case iAbout:
  343.             NoteAlert( kBaseResID , nil );
  344.             break;
  345.         default:
  346.             appleMenu = GetMHandle( mApple );
  347.             GetItem( appleMenu, item, accName );
  348.             accNumber = OpenDeskAcc( accName );
  349.             break;
  350.     }
  351. }
  352.  
  353.  
  354. /****************** HandleFileChoice ***********************/
  355.  
  356. void    HandleFileChoice( short item )
  357. {
  358.     ReminderPtr    reminder;
  359.     
  360.     switch ( item )
  361.     {
  362.         case iSetReminder:
  363.             reminder = HandleDialog();
  364.             if ( reminder )
  365.                 ScheduleReminder( reminder );
  366.             break;
  367.         case iQuit :
  368.             gDone = true;
  369.             break;
  370.     }
  371. }
  372.  
  373.  
  374. /******************** GetFirstReminder **************************/
  375.  
  376. ReminderPtr    GetFirstReminder( void )
  377. {
  378.     return( (ReminderPtr)gReminderQueue.qHead );
  379. }
  380.  
  381.  
  382. /******************** GetNextReminder **************************/
  383.  
  384. ReminderPtr    GetNextReminder( ReminderPtr reminder )
  385. {
  386.     return( (ReminderPtr)reminder->queue.qLink );
  387. }
  388.  
  389.  
  390. /******************** FindReminderOnMenu ************************/
  391.  
  392. ReminderPtr    FindReminderOnMenu( short menuItem )
  393. {
  394.     ReminderPtr    theReminder;
  395.     
  396.     theReminder = GetFirstReminder();
  397.     while ( theReminder )
  398.     {
  399.         if ( theReminder->menuItem == menuItem )
  400.             break;
  401.         theReminder = GetNextReminder( theReminder );
  402.     }
  403.     return( theReminder );
  404. }
  405.  
  406.  
  407. /******************** FindReminderToPost ************************/
  408.  
  409. ReminderPtr    FindReminderToPost( short hour, short minute )
  410. {
  411.     ReminderPtr    theReminder;
  412.     
  413.     theReminder = GetFirstReminder();
  414.     while ( theReminder )
  415.     {
  416.         if ( (!theReminder->wasPosted)
  417.             && (theReminder->hour <= hour)
  418.             && (theReminder->minute <= minute) )
  419.         
  420.             break;
  421.         theReminder = GetNextReminder (theReminder);
  422.     }
  423.     return( theReminder );
  424. }
  425.  
  426.  
  427. /******************** FindReminderToDispose **********************/
  428.  
  429. ReminderPtr    FindReminderToDispose( void )
  430. {
  431.     ReminderPtr    theReminder;
  432.     
  433.     theReminder = GetFirstReminder ();
  434.     while ( theReminder )
  435.     {
  436.         if ( theReminder->dispose )
  437.             break;
  438.         theReminder = GetNextReminder (theReminder);
  439.     }
  440.     return( theReminder );
  441. }
  442.  
  443.  
  444. /******************** InsertReminderIntoMenu ************************/
  445.  
  446. void    InsertReminderIntoMenu( ReminderPtr reminder )
  447. {
  448.     short    itemBefore;
  449.     MenuHandle reminderMenu;
  450.     
  451.     reminderMenu = GetMenu( mReminders );
  452.  
  453.     itemBefore = CountRemindersOnMenu();
  454.     
  455.     InsMenuItem( reminderMenu, reminder->menuString, itemBefore );
  456.     
  457.     reminder->menuItem = itemBefore + 1;
  458. }
  459.  
  460. /********************* CountRemindersOnMenu ************************/
  461.  
  462. short    CountRemindersOnMenu( void )
  463. {
  464.     MenuHandle reminderMenu;
  465.     
  466.     reminderMenu = GetMenu( mReminders );
  467.  
  468.     return( CountMItems( reminderMenu ) );
  469. }
  470.  
  471.  
  472. /*********************** DeleteReminderFromMenu ***************************/
  473.  
  474. void    DeleteReminderFromMenu( ReminderPtr reminder )
  475. {
  476.     MenuHandle reminderMenu;
  477.     
  478.     reminderMenu = GetMenu( mReminders );
  479.     RenumberTrailingReminders( reminder );
  480.     DelMenuItem( reminderMenu, reminder->menuItem );
  481.     reminder->menuItem = 0;
  482. }
  483.  
  484.  
  485. /********************* RenumberTrailingReminders ************************/
  486.  
  487. void    RenumberTrailingReminders( ReminderPtr reminder )
  488. {
  489.     short        count;
  490.     
  491.     count = reminder->menuItem;
  492.     reminder = GetNextReminder( reminder );
  493.     while ( reminder )
  494.     {
  495.         if (reminder->menuItem != 0)
  496.             reminder->menuItem = count++;
  497.         reminder = GetNextReminder( reminder );
  498.     }
  499. }
  500.  
  501.  
  502. /*********************** ScheduleReminder ********************************/
  503.  
  504. void    ScheduleReminder( ReminderPtr reminder )
  505. {
  506.     Enqueue( &reminder->queue, &gReminderQueue );
  507.     InsertReminderIntoMenu( reminder );
  508. }
  509.  
  510.  
  511. /*********************** PostReminder *************************************/
  512.  
  513. void    PostReminder( ReminderPtr reminder )
  514. {
  515.     reminder->notify.nmRefCon = (long)reminder;
  516.     reminder->wasPosted = true;
  517.     NMInstall( &reminder->notify );
  518. }
  519.  
  520.  
  521. /*********************** DeleteReminder ********************************/
  522.  
  523. void    DeleteReminder( ReminderPtr reminder )
  524. {
  525.     if ( reminder->menuItem )
  526.         DeleteReminderFromMenu( reminder );
  527.     reminder->dispose = true;
  528. }
  529.  
  530.  
  531. /************************ DisposeReminder ******************************/
  532.  
  533. ReminderPtr        DisposeReminder( ReminderPtr reminder )
  534. {
  535.     ReminderPtr    next;
  536.     
  537.     if (reminder->menuItem)
  538.         DeleteReminderFromMenu( reminder );
  539.     next = (ReminderPtr)reminder->queue.qLink;
  540.     Dequeue( &reminder->queue, &gReminderQueue );
  541.     DisposePtr( (Ptr)reminder );
  542.     return( next );
  543. }
  544.  
  545.  
  546. /********************************    GetFileName    *******/
  547.  
  548. void    GetFileName( StandardFileReply *replyPtr )
  549. {
  550.     SFTypeList    typeList;
  551.     short        numTypes;
  552.     
  553.     typeList[ 0 ] = 'APPL';
  554.     numTypes = 1;
  555.  
  556.     StandardGetFile( nil, numTypes, typeList, replyPtr );
  557. }
  558.  
  559.  
  560. /******************************** HandleDialog *********/
  561.  
  562. ReminderPtr HandleDialog( void )
  563. {
  564.     DialogPtr            dialog;
  565.     Boolean                dialogDone = false;
  566.     short                itemHit, itemType;
  567.     Handle                textItemHandle;
  568.     Handle                itemHandle;
  569.     Handle                okItemHandle;
  570.     Handle                launchItemHandle;
  571.     Rect                itemRect;
  572.     Str255                itemText;
  573.     StandardFileReply    reply;
  574.     ReminderPtr            reminder;
  575.     
  576.     dialog = GetNewDialog( kDialogResID, nil, kMoveToFront );
  577.  
  578.     ShowWindow( dialog );
  579.     SetPort( dialog );
  580.     
  581.     reminder = (ReminderPtr)NewPtr( sizeof ( ReminderRec ) );
  582.     reminder->menuItem = 0;
  583.     reminder->dispose = false;
  584.     reminder->wasPosted = false;
  585.  
  586.     SetDialogDefaultItem( dialog, ok );
  587.     SetDialogCancelItem( dialog, cancel );
  588.     SetDialogTracksCursor( dialog, true );
  589.     
  590.     GetDItem( dialog, iMessageText, &itemType, &textItemHandle, &itemRect );
  591.     GetDItem( dialog, ok, &itemType, &okItemHandle, &itemRect );
  592.     GetDItem( dialog, iLaunchCheckBox, &itemType, &launchItemHandle, &itemRect );
  593.     SelIText( dialog, iMessageText, kMinTextPosition, kMaxTextPosition );
  594.     
  595.     while ( ! dialogDone )
  596.     {            
  597.         GetIText( textItemHandle, itemText );
  598.  
  599.         if ( itemText[ 0 ] == 0 && !GetCtlValue( (ControlHandle)launchItemHandle ) )
  600.             HiliteControl( (ControlHandle)okItemHandle, kDisableButton );
  601.         else
  602.             HiliteControl( (ControlHandle)okItemHandle, kEnableButton );
  603.             
  604.         ModalDialog( nil, &itemHit );
  605.  
  606.         switch ( itemHit )
  607.         {
  608.             case ok:
  609.             case cancel:
  610.                 dialogDone = true;
  611.                 break;
  612.             case iSoundCheckBox:
  613.             case iRotateCheckBox:
  614.                 GetDItem( dialog, itemHit, &itemType, &itemHandle, &itemRect );
  615.                 SetCtlValue( (ControlHandle)itemHandle, ! GetCtlValue( (ControlHandle)itemHandle ) );
  616.                 break;
  617.             case iLaunchCheckBox:
  618.             case iAppNameText:
  619.                 if ( ! GetCtlValue( (ControlHandle)launchItemHandle ) )
  620.                 {
  621.                     GetFileName( &reply );
  622.                     if ( reply.sfGood )
  623.                     {
  624.                         SetCtlValue( (ControlHandle)launchItemHandle, kOn );
  625.                         reminder->file = reply.sfFile;
  626.                         GetDItem( dialog, iAppNameText, &itemType, &itemHandle, &itemRect );
  627.                         SetIText( itemHandle, reminder->file.name );
  628.                     }
  629.                 }
  630.                 else 
  631.                 {
  632.                     SetCtlValue( (ControlHandle)launchItemHandle, kOff );
  633.                     GetDItem( dialog, iAppNameText, &itemType, &itemHandle, &itemRect );
  634.                     SetIText( itemHandle, "\p<Not Selected>" );
  635.                 }
  636.                 break;
  637.         }
  638.     }
  639.     
  640.     if ( itemHit == cancel )
  641.     {
  642.         DisposePtr( (Ptr)reminder );
  643.         reminder = nil;
  644.     } else
  645.         CopyDialogToReminder( dialog, reminder );
  646.  
  647.     DisposDialog( dialog );
  648.     
  649.     return( reminder );
  650. }
  651.  
  652. /************************************* CopyDialogToReminder */
  653.  
  654. void         CopyDialogToReminder( DialogPtr dialog, ReminderPtr reminder)
  655. {
  656.     short        itemType;
  657.     Rect        itemRect;
  658.     Handle        itemHandle;
  659.     Str255        string;
  660.     MenuHandle    menu;
  661.     short        val;
  662.     long        tmp;
  663. /*
  664.  *    This change was made in June, 92 and is not in the first printing of the book
  665.  */
  666.      struct PopupPrivateData        **popupDataHandle;
  667. /*
  668.  *    End of change
  669.  */
  670.     
  671.     
  672.     GetDItem( dialog, iMessageText, &itemType, &itemHandle, &itemRect );
  673.     GetIText( itemHandle, reminder->alert );
  674.     reminder->notify.nmStr = (StringPtr)&reminder->alert;
  675.  
  676.     GetDItem( dialog, iSoundCheckBox, &itemType, &itemHandle, &itemRect );
  677.     if ( GetCtlValue( (ControlHandle)itemHandle ) )
  678.         reminder->notify.nmSound =  (Handle)-1L;
  679.     else
  680.         reminder->notify.nmSound = nil;
  681.  
  682.     GetDItem( dialog, iRotateCheckBox, &itemType, &itemHandle, &itemRect );
  683.     if( GetCtlValue( (ControlHandle)itemHandle ) )
  684.         reminder->notify.nmIcon = GetResource( 'SICN', kBaseResID );
  685.     else
  686.         reminder->notify.nmIcon = nil;
  687.  
  688.     GetDItem( dialog, iLaunchCheckBox, &itemType, &itemHandle, &itemRect );
  689. /*
  690.  *    This change was made in June, 92 and is not in the first printing of the book
  691.  */
  692.     if( reminder->launch = GetCtlValue( (ControlHandle)itemHandle ) )
  693.         reminder->notify.nmResp = gLaunchResponseUPP;
  694.     else
  695.         reminder->notify.nmResp = gNormalResponseUPP;
  696. /*
  697.  *    End of change
  698.  */
  699.  
  700.     GetDItem( dialog, iHoursPopup, &itemType, &itemHandle, &itemRect );
  701.     val = GetCtlValue( (ControlHandle)itemHandle );
  702.     NumToString( (long) val, string );
  703.     StringToNum ( string, &tmp );
  704.     reminder->hour = tmp;
  705.     
  706.     reminder->menuString[0] = 0;
  707.     ConcatString( reminder->menuString, string );
  708.     ConcatString( reminder->menuString, "\p:" );
  709.  
  710.     GetDItem( dialog, iMinutesPopup, &itemType, &itemHandle, &itemRect );
  711.     val = GetCtlValue( (ControlHandle)itemHandle );
  712.     
  713. /*
  714.  *    This change was made in June, 92 and is not in the first printing of the book
  715.  */
  716.     popupDataHandle = (struct PopupPrivateData **)
  717.                   ((**(ControlHandle)itemHandle).contrlData);
  718.     menu = (**popupDataHandle).mHandle;
  719. /*
  720.  *    End of change
  721.  */
  722.     
  723.     GetItem( menu, val, string );
  724.     StringToNum ( string, &tmp );
  725.     reminder->minute = tmp;
  726.     
  727.     ConcatString( reminder->menuString, string );
  728.     ConcatString( reminder->menuString, "\p ");
  729.  
  730.     GetDItem( dialog, iAMorPMPopup, &itemType, &itemHandle, &itemRect );
  731.     val = GetCtlValue( (ControlHandle)itemHandle );
  732.     
  733.     if( val == kPM ) 
  734.         reminder->hour += 12;
  735.  
  736.     menu = GetMenu ( mAMorPM );
  737.     GetItem( menu, val, string );
  738.     ConcatString( reminder->menuString, string );    
  739.     
  740.     reminder->notify.qType = nmType;
  741.     reminder->notify.nmMark = kMarkApp;
  742. }
  743.  
  744. /************************** ConcatString ************/
  745.  
  746. void    ConcatString( Str255 str1, Str255 str2)
  747. {
  748.     short i;
  749.     
  750.     for (i=str1[0];i<str2[0]+str1[0];i++)
  751.     {
  752.         str1[i+1]=str2[i-str1[0]+1];
  753.     }
  754.     str1[0]=i;
  755. }
  756.  
  757. /************************** NormalResponse ************/
  758.  
  759. pascal    void    NormalResponse( NMRecPtr notifyPtr )
  760. {
  761.     ReminderPtr    reminder;
  762.     OSErr        err;
  763.     
  764.     reminder = GetReminderFromNotification( notifyPtr );
  765.     err = NMRemove( notifyPtr );
  766.     reminder->dispose = true;
  767. }
  768.  
  769.  
  770. /**************************    LaunchResponse    *******/
  771.  
  772. pascal    void    LaunchResponse( NMRecPtr notifyPtr )
  773. {
  774.     LaunchParamBlockRec    launchParams;
  775.     OSErr        err;
  776.     FSSpec        fileSpec;
  777.     ReminderPtr    reminder;
  778.     Boolean        isFolder;
  779.     Boolean        wasAlias;
  780.     
  781.     reminder = GetReminderFromNotification( notifyPtr );
  782.     
  783.     fileSpec = reminder->file;
  784.     
  785.     err = ResolveAliasFile( &fileSpec, true, &isFolder, &wasAlias );
  786.     
  787.     launchParams.launchBlockID = extendedBlock;
  788.     launchParams.launchEPBLength = extendedBlockLen;
  789.     launchParams.launchFileFlags = 0;
  790.     launchParams.launchControlFlags = launchContinue + launchNoFileFlags;
  791.     launchParams.launchAppSpec = &fileSpec;
  792.     
  793.     launchParams.launchAppParameters = nil;
  794.     
  795.     if ( LaunchApplication( &launchParams ) ) SysBeep( 20 );
  796.     
  797.     err = NMRemove( notifyPtr );
  798.     
  799.     reminder->dispose = true;
  800. }
  801.  
  802. /************************** GetReminderFromNotification ************/
  803.  
  804. ReminderPtr        GetReminderFromNotification( NMRecPtr notifyPtr )
  805. {
  806.     return (ReminderPtr) notifyPtr->nmRefCon;
  807. }